package service

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"net/http"
	"smart-sensor-cloud/internal/model"
	"smart-sensor-cloud/pkg/auth"
	"smart-sensor-cloud/pkg/middleware"
	"smart-sensor-cloud/pkg/util"
	"strconv"
)

type ChangePasswordStruct struct {
	Username    string `json:"username"`
	Password    string `json:"password"`
	NewPassword string `json:"newPassword"`
}

func AddUser(ctx *gin.Context) {
	user := new(model.User)
	if err := ctx.MustBindWith(user, binding.JSON); err != nil {
		ctx.Set("error", util.NewInvalidParameterError(err.Error()))
		return
	}

	if user.Password == "" {
		ctx.Set("error", util.NewInvalidParameterError("用户密码不可以为空"))
		return
	}

	if duplicated, err := model.GetUserByUsername(user.Username); err != nil {
		if !errors.Is(err, model.ErrUserNotFound) {
			ctx.Set("error", &util.Error{
				Code:    http.StatusInternalServerError,
				Message: err.Error(),
			})
			return
		}
	} else if duplicated != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: fmt.Sprintf("用户名为%s的用户已存在", user.Username),
		})
		return
	}

	if err := model.AddUser(user); err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	auth.LoadCasbinPolicy(ctx)

	util.ResponseOK(ctx, util.OK())
}

type UserLoginInfo struct {
	*model.User
}

func GetJWTClaimsFromContext(ctx *gin.Context) (*auth.UserClaims, error) {
	jwtGenerator := ctx.MustGet(middleware.JWTGeneratorKey).(*auth.JWTGenerator)

	claims, err := jwtGenerator.ParseTokenToClaims(GetToken(ctx))
	if err != nil {
		return nil, err
	}

	return claims, nil
}

func GetUserInfo(ctx *gin.Context) {
	claims, err := GetJWTClaimsFromContext(ctx)
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	user, err := model.GetUserByID(claims.UserID)
	if err != nil {
		if errors.Is(err, model.ErrUserNotFound) {
			ctx.Set("error", util.NewResourceNotFoundError(err.Error()))
		} else {
			ctx.Set("error", &util.Error{
				Code:    http.StatusInternalServerError,
				Message: err.Error(),
			})
		}
		return
	}

	role, err := model.GetRoleWithID(claims.RoleID)
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}
	user.Role = role

	util.ResponseOK(ctx, util.OKWithPayload(&UserLoginInfo{user}))
}

func GetUserWithID(ctx *gin.Context) {
	idStr := ctx.Param("id")
	if idStr == "" {
		ctx.Set("error", util.NewInvalidParameterError("非法的请求参数"))
		return
	}

	id, err := strconv.Atoi(idStr)
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	user, err := model.GetUserByID(id)
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	ur, err := model.GetUserRoleWithUserID(int(user.ID))
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	role, err := model.GetRoleWithID(int(ur.ID))
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}
	user.Role = role

	util.ResponseOK(ctx, util.OKWithPayload(user))
}

func GetUsers(ctx *gin.Context) {
	sizeStr := ctx.DefaultQuery("size", "10")
	indexStr := ctx.DefaultQuery("page", "1")

	size, err := strconv.Atoi(sizeStr)
	if err != nil {
		ctx.Set("error", util.NewInvalidParameterError("参数转换失败"))
		return
	}
	index, err := strconv.Atoi(indexStr)
	if err != nil {
		ctx.Set("error", util.NewInvalidParameterError("参数转换失败"))
		return
	}

	users, total, err := model.GetUsers(index, size)
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	util.ResponseOK(ctx, util.OKWithPayload(&util.PaginationResp{
		Size:  size,
		Index: index,
		Data:  users,
		Total: total,
	}))
}

func DeleteUser(ctx *gin.Context) {
	idStr := ctx.Param("id")
	if idStr == "" {
		ctx.Set("error", util.NewInvalidParameterError("非法的请求参数"))
		return
	}

	id, err := strconv.Atoi(idStr)
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	if err := model.DeleteUser(id); err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: fmt.Sprintf("删除用户失败, %s", err),
		})
		return
	}

	auth.LoadCasbinPolicy(ctx)
	util.ResponseOK(ctx, util.OK())
}

func ChangePwdWithUsername(ctx *gin.Context) {
	params := new(ChangePasswordStruct)
	if err := ctx.MustBindWith(params, binding.JSON); err != nil {
		ctx.Set("error", util.NewInvalidParameterError(err.Error()))
		return
	}
	if params.Password == "" || params.NewPassword == "" {
		ctx.Set("error", util.NewInvalidParameterError("用户密码不可以为空"))
		return
	}

	user := new(model.User)
	user.Username = params.Username
	user.Password = params.Password

	if err := model.ChangeUserPassword(params.NewPassword, user); err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}
	util.ResponseOK(ctx, util.OK())
}

func UpdateUser(ctx *gin.Context) {
	userIDStr := ctx.Param("id")

	userID, err := strconv.Atoi(userIDStr)
	if err != nil {
		ctx.Set("error", util.NewInvalidParameterError("非法的请求参数"))
		return
	}
	change := new(model.User)

	if err := ctx.MustBindWith(change, binding.JSON); err != nil {
		ctx.Set("error", util.NewInvalidParameterError(err.Error()))
		return
	}

	if err := model.UpdateUser(userID, change); err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	auth.LoadCasbinPolicy(ctx)
	util.ResponseOK(ctx, util.OK())
}

func UpdateUserRole(ctx *gin.Context) {
	change := new(model.UserRole)

	if err := ctx.MustBindWith(change, binding.JSON); err != nil {
		ctx.Set("error", util.NewInvalidParameterError(err.Error()))
		return
	}

	//userID, err := strconv.Atoi(userIDStr)
	//if err != nil {
	//	ctx.Set("error", util.NewInvalidParameterError("非法的请求参数"))
	//	return
	//}
	//roleID, err := strconv.Atoi(RoleIDStr)
	//if err != nil {
	//	ctx.Set("error", util.NewInvalidParameterError("非法的请求参数"))
	//	return
	//}

	if err := model.UpdateUserRoleWithUserID(change.RoleID, change.UserID); err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	auth.LoadCasbinPolicy(ctx)
	util.ResponseOK(ctx, util.OK())
}

func GetCurrentUserMenuTree(ctx *gin.Context) {
	claims, err := GetJWTClaimsFromContext(ctx)
	if err != nil {
		ctx.Set("error", &util.Error{
			Code:    http.StatusInternalServerError,
			Message: err.Error(),
		})
		return
	}

	user, err := model.GetUserByID(claims.UserID)
	if err != nil {
		ctx.Set("error", util.NewResourceNotFoundError("无法找到对应的用户"))
		return
	}

	// FIXME: 先采用Hard-code的方式判断是否为Root用户（Root用户拥有最高权限）, 后面修改为根据配置文件中的用户名和角色来判断
	// 如果为Root用户，直接显示所有的菜单
	if user.ID == 1 {
		menus, err := model.GetAllMenus(nil)
		if err != nil {
			ctx.Set("error", &util.Error{
				Code:    http.StatusInternalServerError,
				Message: err.Error(),
			})
			return
		}

		menuTrees := menus.ToTree()

		util.ResponseOK(ctx, util.OKWithPayload(menuTrees))
		return
	} else {
		role, err := model.GetRoleWithID(claims.RoleID)
		if err != nil {
			ctx.Set("error", util.NewResourceNotFoundError(err.Error()))
			return
		}

		menuIDs := role.RoleMenus.ToMenuIDs()

		menus, err := model.GetMenuWithIDs(menuIDs)
		if err != nil {
			ctx.Set("error", &util.Error{
				Code:    http.StatusInternalServerError,
				Message: err.Error(),
			})
			return
		}

		menuTrees := menus.ToTree()
		util.ResponseOK(ctx, util.OKWithPayload(menuTrees))
		return
	}
}
